// Copyright DustedPixels.com 2008. All rights reserved.

package com.dustedpixels.asm;

import java.util.HashMap;
import java.util.Map;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;

/**
 * @author micapolos@gmail.com (Michal Pociecha-Los)
 */
public final class LabelFixingMethodVisitor extends MethodAdapter {

  private final Map<Label, Label> visitedLabels;

  public LabelFixingMethodVisitor(MethodVisitor out) {
    super(out);
    visitedLabels = new HashMap<Label, Label>();    
  }

  @Override
  public void visitLabel(Label label) {
    super.visitLabel(getLabel(label));
  }

  @Override
  public void visitJumpInsn(int opcode, Label label) {
    super.visitJumpInsn(opcode, getLabel(label));
  }

  @Override
  public void visitLineNumber(int line, Label start) {
    super.visitLineNumber(line, getLabel(start));
  }

  @Override
  public void visitLocalVariable(String name, String desc, String signature, Label start,
      Label end, int index) {
    super.visitLocalVariable(name, desc, signature, getLabel(start), getLabel(end), index);
  }

  @Override
  public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
    super.visitLookupSwitchInsn(getLabel(dflt), keys, getLabels(labels));
  }

  @Override
  public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
    super.visitTableSwitchInsn(min, max, getLabel(dflt), getLabels(labels));
  }

  @Override
  public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
    super.visitTryCatchBlock(getLabel(start), getLabel(end), getLabel(handler), type);
  }
  
  private Label getLabel(Label label) {
    Label resultLabel = visitedLabels.get(label);
    if (resultLabel == null) {
      resultLabel = new Label();
      visitedLabels.put(label, resultLabel);
    }
    return resultLabel;
  }

  private Label[] getLabels(Label[] labels) {
    Label[] resultLabels = new Label[labels.length];
    for (int i = 0; i < labels.length; i++) {
      resultLabels[i] = getLabel(labels[i]);
    }
    return resultLabels;
  }
}
